﻿using System.Collections.Generic;
using UnityEngine;

namespace Core
{
    public static partial class Utils
    {
        #region Transform gameobject
        public static void SetParent(this Transform trans, IGameObject parent)
        {
            if (trans == null || parent == null) return;

            trans.SetParent(parent.transform);
        }

        public static void SetParent(this GameObject go, Transform parent)
        {
            if (go == null || parent == null) return;

            go.transform.SetParent(parent);
        }

        public static void SetParent(this GameObject go, GameObject parent)
        {
            if (go == null || parent == null) return;

            go.transform.SetParent(parent.transform);
        }

        public static void SetParent(this IGameObject go, GameObject parent)
        {
            if (go == null || parent == null) return;

            go.transform.SetParent(parent.transform);
        }

        public static void SetParent(this IGameObject go, IGameObject parent)
        {
            if (go == null || parent == null) return;

            go.transform.SetParent(parent.transform);
        }

        public static void Reset(this Transform trans)
        {
            if (trans == null) return;

            trans.localScale = Vector3.one;
            //trans.SetLocalPositionAndRotation(Vector3.zero, Quaternion.identity);
            trans.localPosition = Vector3.zero;
            trans.localRotation = Quaternion.identity;
        }

        public static void Reset(this GameObject go)
        {
            go.transform.Reset();
        }

        public static void SetLayer(this GameObject go, int layer)
        {
            if (go == null)
            {
                return;
            }

            SetLayer(go.transform, layer);
        }

        public static void SetLayer(this Transform trans, int layer)
        {
            if (trans == null)
            {
                return;
            }

            trans.gameObject.layer = layer;
            for (int i = 0; i < trans.childCount; ++i)
            {
                SetLayer(trans.GetChild(i), layer);
            }
        }

        public static void SetLayer(this IGameObject go, int layer)
        {
            if (go == null)
            {
                return;
            }
            SetLayer(go.transform, layer);
        }

        public static void SetLocalScale(this GameObject go, float scale)
        {
            if (go == null) return;

            go.transform.localScale = Vector3.one * scale;
        }

        public static void AddLocalPosX(this Transform trans, float x)
        {
            var pos = trans.localPosition;
            pos.x += x;
            trans.localPosition = pos;
        }

        public static void AddLocalPosY(this Transform trans, float y)
        {
            var pos = trans.localPosition;
            pos.y += y;
            trans.localPosition = pos;
        }

        public static void AddLocalPosZ(this Transform trans, float z)
        {
            var pos = trans.localPosition;
            pos.z += z;
            trans.localPosition = pos;
        }

        public static void SetLocalPosX(this Transform trans, float x)
        {
            var pos = trans.localPosition;
            pos.x = x;
            trans.localPosition = pos;
        }

        public static void SetLocalPosY(this Transform trans, float y)
        {
            var pos = trans.localPosition;
            pos.y = y;
            trans.localPosition = pos;
        }

        public static void SetLocalPosZ(this Transform trans, float z)
        {
            var pos = trans.localPosition;
            pos.z = z;
            trans.localPosition = pos;
        }

        public static void AddPosX(this Transform trans, float x)
        {
            var pos = trans.position;
            pos.x += x;
            trans.position = pos;
        }

        public static void AddPosY(this Transform trans, float y)
        {
            var pos = trans.position;
            pos.y += y;
            trans.position = pos;
        }

        public static void AddPosZ(this Transform trans, float z)
        {
            var pos = trans.position;
            pos.z += z;
            trans.position = pos;
        }
        public static void SetPosX(this Transform trans, float x)
        {
            var pos = trans.position;
            pos.x = x;
            trans.position = pos;
        }

        public static void SetPosY(this Transform trans, float y)
        {
            var pos = trans.position;
            pos.y = y;
            trans.position = pos;
        }

        public static void SetPosZ(this Transform trans, float z)
        {
            var pos = trans.position;
            pos.z = z;
            trans.position = pos;
        }
        #endregion

        public static class Trans
        {
            public static bool Inside(Transform trans, Vector3 left_up, Vector3 right_down)
            {
                var pos = trans.position;
                if (pos.x > left_up.x && pos.x > right_down.x ||
                    pos.x < left_up.x && pos.x < right_down.x)
                {
                    return false;
                }
                if (pos.z > left_up.z && pos.z > right_down.z ||
                    pos.z < left_up.z && pos.z < right_down.z)
                {
                    return false;
                }

                return true;
            }

            public static void SetActive(GameObject go, bool active)
            {
                if (go == null || go.activeSelf == active) return;

                go.SetActive(active);
            }



            public static GameObject Find(GameObject parent, string name, bool auto_create = false)
            {
                if (parent == null) return null;

                var trans = parent.transform.Find(name);

                if (trans != null)
                {
                    return trans.gameObject;
                }

                if (auto_create)
                {
                    trans = Create(parent.transform, name);
                    return trans.gameObject;
                }

                return null;
            }


            /// <summary>
            /// 在指定节点的下方创建一个新的GameObject
            /// </summary>
            /// <param name="parent">父节点</param>
            /// <param name="name">名称</param>
            /// <returns>新节点Trans</returns>
            public static Transform Create(Transform parent, string name)
            {
                if (parent == null) return null;

                GameObject go = new GameObject(name);
                Transform trans = go.transform;
                trans.SetParent(parent);
                trans.localPosition = Vector3.zero;
                trans.localScale = Vector3.one;
                trans.localRotation = Quaternion.identity;
                go.name = name;
                return trans;
            }

            public static string GetPath(Transform trans)
            {
                if (trans == null)
                {
                    return string.Empty;
                }
                string path = trans.name;
                while (trans.parent != null)
                {
                    trans = trans.parent;
                    path = $"{trans.name}/{path}";
                }

                return path;
            }

            //2D向量旋转
            public static void Rotate2D(Transform trans, Vector2 dir)
            {
                float angle = Vector3.SignedAngle(Vector3.left, dir, Vector3.forward);
                trans.rotation = Quaternion.Euler(0, 0, angle);
            }

            /// <summary>
            /// 是否直系节点关系
            /// </summary>
            /// <param name="child"></param>
            /// <param name="parent"></param>
            /// <returns></returns>
            public static bool IsDirectRelative(Transform child, Transform parent)
            {
                while (child.parent != null)
                {
                    if (child.parent == parent)
                    {
                        return true;
                    }
                    child = child.parent;
                }
                return false;
            }

            public static void DestroyImmediate(GameObject go)
            {
                if (go == null) return;

                GameObject.DestroyImmediate(go);
            }

            public static void Destroy(GameObject go)
            {
                if (go == null) return;

                GameObject.Destroy(go);
            }

            public static void RemoveAllChildren(GameObject parent)
            {
                for (int i = 0; i < parent.transform.childCount; i++)
                {
                    var transform = parent.transform.GetChild(i);
                    GameObject.Destroy(transform.gameObject);
                }
            }


            public static float GetGroundHeight(Vector3 pos, float high = 500f)
            {
                //if (Physics.Raycast(pos + Vector3.up * 100f, Vector3.down, out hitInfo, 500, Layer._GroundLayer | Layer._Floor | Layer._HillLayer))
                if (Physics.Raycast(pos + Vector3.up * 100f, Vector3.down, out var hitInfo, 500))
                {
                    return hitInfo.point.y;
                }
                return pos.y;
            }

            private static Stack<GameObject> mTempStack = new();
            public static void Delete(Stack<GameObject> stack, GameObject go)
            {
                if (stack == null || go == null)
                {
                    return;
                }
                if (stack.Contains(go) == false)
                {
                    return;
                }

                mTempStack.Clear();

                while (stack.Count > 0)
                {
                    var ele = stack.Pop();
                    if (ele == go)
                    {
                        break;
                    }
                    mTempStack.Push(ele);
                }

                while (mTempStack.Count > 0)
                {
                    stack.Push(mTempStack.Pop());
                }
            }
        }
    }
}
